package com.rxyb.toolize.image;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;

/**
 * 图片处理
 *
 * @coder duyh,@auth duyh
 * @date May 13, 2020
 */
public class ImageTools {

    /**
     * 图片缩放.
     *
     * @param openUrl
     * @param saveUrl
     * @param width   需要的宽度
     * @param height  需要的高度
     * @throws Exception
     */
    public static void zoom(String openUrl, String saveUrl, int width, int height) throws Exception {
        // 获取图片格式
        String[] arr = openUrl.split(".");
        String suffix = arr[arr.length - 1];
        double sx = 0.0;
        double sy = 0.0;
        File file = new File(openUrl);
        if (!file.isFile()) {
            throw new Exception("ImageDeal>>>" + file + " 不是一个图片文件!");
        }
        // 读取该图片
        BufferedImage bi = ImageIO.read(file);
        // 计算x轴y轴缩放比例--如需等比例缩放，在调用之前确保参数width和height是等比例变化的
        sx = (double) width / bi.getWidth();
        sy = (double) height / bi.getHeight();
        AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(sx, sy), null);
        // File sf = new File(saveUrl, saveName + "." + suffix);
        File sf = new File(saveUrl);
        Image zoomImage = op.filter(bi, null);
        try {
            // 保存图片
            boolean flag = ImageIO.write((BufferedImage) zoomImage, suffix, sf);
            System.out.println("输出缩放图片结果：" + flag);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 旋转
     *
     * @param openUrl
     * @param saveUrl
     * @param degree  旋转角度
     * @throws Exception
     */
    public static void spin(String openUrl, String saveUrl, int degree) throws Exception {
        // 获取图片格式
        String[] arr = openUrl.split(".");
        String suffix = arr[arr.length - 1];
        // 旋转后的宽度
        int swidth = 0;
        // 旋转后的高度
        int sheight = 0;
        // 原点横坐标
        int x;
        // 原点纵坐标
        int y;
        File file = new File(openUrl);
        if (!file.isFile()) {
            throw new Exception("ImageDeal>>>" + file + " 不是一个图片文件!");
        }
        // 读取该图片
        BufferedImage bi = ImageIO.read(file);
        // 处理角度--确定旋转弧度
        degree = degree % 360;
        // 将角度转换到0-360度之间
        if (degree < 0)
            degree = 360 + degree;
        // 将角度转为弧度
        double theta = Math.toRadians(degree);
        // 确定旋转后的宽和高
        if (degree == 180 || degree == 0 || degree == 360) {
            swidth = bi.getWidth();
            sheight = bi.getHeight();
        } else if (degree == 90 || degree == 270) {
            sheight = bi.getWidth();
            swidth = bi.getHeight();
        } else {
            swidth = (int) (Math.sqrt(bi.getWidth() * bi.getWidth() + bi.getHeight() * bi.getHeight()));
            sheight = (int) (Math.sqrt(bi.getWidth() * bi.getWidth() + bi.getHeight() * bi.getHeight()));
        }
        // 确定原点坐标
        x = (swidth / 2) - (bi.getWidth() / 2);
        y = (sheight / 2) - (bi.getHeight() / 2);
        // 设置图片背景颜色
        BufferedImage spinImage = new BufferedImage(swidth, sheight, bi.getType());
        Graphics2D gs = (Graphics2D) spinImage.getGraphics();
        gs.setColor(Color.white);
        gs.fillRect(0, 0, swidth, sheight);
        // 以给定颜色绘制旋转后图片的背景
        AffineTransform at = new AffineTransform();
        at.rotate(theta, swidth / 2, sheight / 2);// 旋转图象
        at.translate(x, y);
        AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
        spinImage = op.filter(bi, spinImage);
        File sf = new File(saveUrl);
        // 保存图片
        boolean flag = ImageIO.write(spinImage, suffix, sf);
        System.out.println("输出旋转图片结果：" + flag);
    }

    /**
     * 马赛克
     *
     * @param imgbyte
     * @param suffix  扩展名
     * @param size    马赛克尺寸，即每个矩形的长宽
     * @return
     * @throws Exception
     */
    public static byte[] mosaic(byte[] imgbyte, String suffix, int size) throws Exception {
        ByteArrayInputStream in = new ByteArrayInputStream(imgbyte);// 将b作为输入流；
        BufferedImage bi = ImageIO.read(in); // 将in作为输入流，读取图片存入image中，而这里in可以为ByteArrayInputStream();

        BufferedImage spinImage = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_RGB);
        if (bi.getWidth() < size || bi.getHeight() < size || size <= 0) { // 马赛克格尺寸太大或太小
            System.err.println("图片小于马赛克大小");
            return null;
        }
        int xcount = 0; // x方向绘制个数
        int ycount = 0; // y方向绘制个数
        if (bi.getWidth() % size == 0) {
            xcount = bi.getWidth() / size;
        } else {
            xcount = bi.getWidth() / size + 1;
        }
        if (bi.getHeight() % size == 0) {
            ycount = bi.getHeight() / size;
        } else {
            ycount = bi.getHeight() / size + 1;
        }
        int x = 0; // 坐标
        int y = 0; // 绘制马赛克(绘制矩形并填充颜色)
        Graphics gs = spinImage.getGraphics();
        for (int i = 0; i < xcount; i++) {
            for (int j = 0; j < ycount; j++) { // 马赛克矩形格大小
                int mwidth = size;
                int mheight = size;
                if (i == xcount - 1) { // 横向最后一个比较特殊，可能不够一个size
                    mwidth = bi.getWidth() - x;
                }
                if (j == ycount - 1) { // 同理
                    mheight = bi.getHeight() - y;
                } // 矩形颜色取中心像素点RGB值
                int centerX = x;
                int centerY = y;
                if (mwidth % 2 == 0) {
                    centerX += mwidth / 2;
                } else {
                    centerX += (mwidth - 1) / 2;
                }
                if (mheight % 2 == 0) {
                    centerY += mheight / 2;
                } else {
                    centerY += (mheight - 1) / 2;
                }
                Color color = new Color(bi.getRGB(centerX, centerY));
                gs.setColor(color);
                gs.fillRect(x, y, mwidth, mheight);
                y = y + size;// 计算下一个矩形的y坐标
            }
            y = 0;// 还原y坐标
            x = x + size;// 计算x坐标
        }
        gs.dispose();

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            ImageIO.write(spinImage, suffix, out);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return out.toByteArray();
    }

    /**
     * 获得指定文件的byte数组
     */
    private static byte[] getBytes(String filePath) {
        byte[] buffer = null;
        try {
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer;
    }

    /**
     * 根据byte数组，生成文件
     */
    public static void getFile(byte[] bfile, String filePath, String fileName) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            File dir = new File(filePath);
            if (!dir.exists() && dir.isDirectory()) {// 判断文件目录是否存在
                dir.mkdirs();
            }
            file = new File(filePath + "\\" + fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

}
